#!/usr/bin/env python
# -*- coding: utf-8 -*-

import os
import json
import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mpl
from matplotlib.gridspec import GridSpec
from datetime import datetime
import pandas as pd
import seaborn as sns
from scipy.stats import gaussian_kde
import matplotlib.gridspec as gridspec


class UAVSimulationVisualizer:
    """
    用于可视化UAV通信仿真结果的类。
    提供多种绘图方法来分析协议性能。
    """
    
    def __init__(self, results_file, output_dir="./figures"):
        """
        初始化可视化器
        
        Args:
            results_file (str或dict): 仿真结果JSON文件的路径或结果字典对象
            output_dir (str): 保存图表的目录
        """
        self.output_dir = output_dir
        
        # 创建输出目录
        if not os.path.exists(output_dir):
            os.makedirs(output_dir)
            
        # 判断results_file类型
        if isinstance(results_file, dict):
            self.results = results_file
        else:
            self.results = self._load_results(results_file)
            
        self.config_plots()
            
    def _load_results(self, results_file):
        """加载仿真结果JSON文件"""
        with open(results_file, 'r', encoding='utf-8') as f:
            return json.load(f)
    
    def config_plots(self):
        """配置绘图环境"""
        # 设置中文字体支持
        try:
            plt.rcParams['font.sans-serif'] = ['SimHei', 'Arial Unicode MS', 'Microsoft YaHei', 'STHeiti']
            plt.rcParams['axes.unicode_minus'] = False
        except:
            # 如果中文字体不可用，则使用默认字体
            pass
            
        # 设置图表样式
        plt.style.use('ggplot')
        mpl.rcParams['figure.figsize'] = [10, 6]
        mpl.rcParams['savefig.dpi'] = 300
        mpl.rcParams['axes.grid'] = True
        mpl.rcParams['grid.alpha'] = 0.3
        
    def _get_protocols_and_stats_key(self):
        """获取协议列表和统计数据的键名
        
        Returns:
            tuple: (protocols列表, 统计数据字典的键名)
        """
        # 确定协议列表
        if 'protocols' in self.results:
            protocols = self.results['protocols']
        elif 'statistics' in self.results:
            protocols = list(self.results['statistics'].keys())
        else:
            return None, None
        
        # 确定统计数据字典的键名
        if 'protocol_stats' in self.results:
            stats_key = 'protocol_stats'
        else:
            stats_key = 'statistics'
        
        return protocols, stats_key
    
    def plot_delivery_rates(self):
        """绘制不同协议的消息传递成功率对比图"""
        # 适应不同的结果格式
        if 'protocols' in self.results:
            protocols = self.results['protocols']
        elif 'statistics' in self.results:
            # 如果没有protocols键，从statistics中获取协议列表
            protocols = list(self.results['statistics'].keys())
        else:
            print("警告: 找不到协议信息")
            return
        
        # 如果protocol_stats存在则使用，否则使用statistics
        if 'protocol_stats' in self.results:
            stats_key = 'protocol_stats'
        else:
            stats_key = 'statistics'
        
        delivery_rates = {}
        for p in protocols:
            if p in self.results[stats_key]:
                if 'delivery_rate' in self.results[stats_key][p]:
                    delivery_rates[p] = self.results[stats_key][p]['delivery_rate']
                elif 'successful_messages' in self.results[stats_key][p] and 'total_messages' in self.results[stats_key][p]:
                    # 计算成功率
                    total = max(1, self.results[stats_key][p]['total_messages'])
                    success = self.results[stats_key][p]['successful_messages']
                    delivery_rates[p] = success / total
        
        if not delivery_rates:
            print("警告: 无法计算传递成功率")
            return
        
        plt.figure(figsize=(12, 6))
        bars = plt.bar(delivery_rates.keys(), delivery_rates.values(), color=sns.color_palette("muted", len(protocols)))
        
        plt.ylabel('消息传递成功率')
        plt.xlabel('通信协议')
        plt.title('不同协议的消息传递成功率对比')
        plt.ylim(0, 1.0)
        
        # 在柱状图上添加数值标签
        for bar in bars:
            height = bar.get_height()
            plt.text(bar.get_x() + bar.get_width()/2., height + 0.01,
                    f'{height:.2%}', ha='center', va='bottom')
        
        plt.grid(axis='y', alpha=0.3)
        plt.tight_layout()
        plt.savefig(os.path.join(self.output_dir, 'delivery_rates.png'))
        plt.close()
    
    def plot_emergency_delivery_rates(self):
        """绘制不同协议的紧急消息传递成功率对比图"""
        # 适应不同的结果格式
        if 'protocols' in self.results:
            protocols = self.results['protocols']
        elif 'statistics' in self.results:
            # 如果没有protocols键，从statistics中获取协议列表
            protocols = list(self.results['statistics'].keys())
        else:
            print("警告: 找不到协议信息")
            return
        
        # 如果protocol_stats存在则使用，否则使用statistics
        if 'protocol_stats' in self.results:
            stats_key = 'protocol_stats'
        else:
            stats_key = 'statistics'
        
        emergency_rates = {}
        for p in protocols:
            if p in self.results[stats_key]:
                if 'emergency_delivery_rate' in self.results[stats_key][p]:
                    emergency_rates[p] = self.results[stats_key][p]['emergency_delivery_rate']
                elif 'emergency_messages_handled' in self.results[stats_key][p] and 'emergency_messages' in self.results[stats_key][p]:
                    # 计算紧急消息成功率
                    total = max(1, self.results[stats_key][p]['emergency_messages'])
                    success = self.results[stats_key][p]['emergency_messages_handled']
                    emergency_rates[p] = success / total
                else:
                    emergency_rates[p] = 0
        
        if not emergency_rates:
            print("警告: 无法计算紧急消息传递成功率")
            return
        
        plt.figure(figsize=(12, 6))
        bars = plt.bar(emergency_rates.keys(), emergency_rates.values(), color=sns.color_palette("bright", len(protocols)))
        
        plt.ylabel('紧急消息传递成功率')
        plt.xlabel('通信协议')
        plt.title('不同协议的紧急消息传递成功率对比')
        plt.ylim(0, 1.0)
        
        # 在柱状图上添加数值标签
        for bar in bars:
            height = bar.get_height()
            plt.text(bar.get_x() + bar.get_width()/2., height + 0.01,
                    f'{height:.2%}', ha='center', va='bottom')
        
        plt.grid(axis='y', alpha=0.3)
        plt.tight_layout()
        plt.savefig(os.path.join(self.output_dir, 'emergency_delivery_rates.png'))
        plt.close()
    
    def plot_average_delays(self):
        """绘制不同协议的平均传输延迟对比图"""
        # 适应不同的结果格式
        if 'protocols' in self.results:
            protocols = self.results['protocols']
        elif 'statistics' in self.results:
            # 如果没有protocols键，从statistics中获取协议列表
            protocols = list(self.results['statistics'].keys())
        else:
            print("警告: 找不到协议信息")
            return
        
        # 如果protocol_stats存在则使用，否则使用statistics
        if 'protocol_stats' in self.results:
            stats_key = 'protocol_stats'
        else:
            stats_key = 'statistics'
        
        delays = {}
        for p in protocols:
            if p in self.results[stats_key]:
                if 'avg_delay' in self.results[stats_key][p]:
                    delays[p] = self.results[stats_key][p]['avg_delay']
        
        if not delays:
            print("警告: 无法获取平均延迟数据")
            return
        
        plt.figure(figsize=(12, 6))
        bars = plt.bar(delays.keys(), delays.values(), color=sns.color_palette("deep", len(protocols)))
        
        plt.ylabel('平均传输延迟 (ms)')
        plt.xlabel('通信协议')
        plt.title('不同协议的平均传输延迟对比')
        
        # 在柱状图上添加数值标签
        for bar in bars:
            height = bar.get_height()
            plt.text(bar.get_x() + bar.get_width()/2., height + 1,
                    f'{height:.2f}ms', ha='center', va='bottom')
        
        plt.grid(axis='y', alpha=0.3)
        plt.tight_layout()
        plt.savefig(os.path.join(self.output_dir, 'average_delays.png'))
        plt.close()
    
    def plot_emergency_delays(self):
        """绘制不同协议的紧急消息平均传输延迟对比图"""
        protocols, stats_key = self._get_protocols_and_stats_key()
        if not protocols:
            print("警告: 找不到协议信息")
            return
            
        emergency_delays = {}
        for p in protocols:
            if p in self.results[stats_key]:
                p_stats = self.results[stats_key][p]
                # 尝试获取紧急消息平均延迟
                if 'emergency_avg_delay' in p_stats:
                    emergency_delays[p] = p_stats['emergency_avg_delay']
                elif 'emergency_delay' in p_stats:
                    emergency_delays[p] = p_stats['emergency_delay']
                elif 'emergency_delays' in p_stats and p_stats['emergency_delays']:
                    # 如果存储了原始延迟列表，计算平均值
                    emergency_delays[p] = sum(p_stats['emergency_delays']) / len(p_stats['emergency_delays'])
                elif 'emergency_messages_handled' in p_stats and p_stats['emergency_messages_handled'] > 0:
                    if 'emergency_total_delay' in p_stats:
                        emergency_delays[p] = p_stats['emergency_total_delay'] / p_stats['emergency_messages_handled']
                    else:
                        # 如果没有直接的延迟数据，使用估计值
                        emergency_delays[p] = p_stats.get('avg_delay', 0) * 0.8  # 假设紧急消息稍快
                else:
                    emergency_delays[p] = 0
        
        if not emergency_delays:
            print("警告: 无法获取紧急消息延迟数据")
            return
            
        plt.figure(figsize=(12, 6))
        bars = plt.bar(emergency_delays.keys(), emergency_delays.values(), color=sns.color_palette("pastel", len(protocols)))
        
        plt.ylabel('紧急消息平均传输延迟 (ms)')
        plt.xlabel('通信协议')
        plt.title('不同协议的紧急消息平均传输延迟对比')
        
        # 在柱状图上添加数值标签
        for bar in bars:
            height = bar.get_height()
            plt.text(bar.get_x() + bar.get_width()/2., height + 1,
                    f'{height:.2f}ms', ha='center', va='bottom')
        
        plt.grid(axis='y', alpha=0.3)
        plt.tight_layout()
        plt.savefig(os.path.join(self.output_dir, 'emergency_delays.png'))
        plt.close()
    
    def plot_deadline_meet_rates(self):
        """绘制不同协议的截止时间满足率对比图"""
        protocols, stats_key = self._get_protocols_and_stats_key()
        if not protocols:
            print("警告: 找不到协议信息")
            return
        
        deadline_rates = {}
        for p in protocols:
            if p in self.results[stats_key]:
                if 'deadline_meet_rate' in self.results[stats_key][p]:
                    deadline_rates[p] = self.results[stats_key][p]['deadline_meet_rate']
                elif 'deadline_met' in self.results[stats_key][p] and 'deadline_messages' in self.results[stats_key][p]:
                    total = max(1, self.results[stats_key][p]['deadline_messages'])
                    met = self.results[stats_key][p]['deadline_met']
                    deadline_rates[p] = met / total
                elif 'missed_deadlines' in self.results[stats_key][p] and 'successful_messages' in self.results[stats_key][p]:
                    successful = max(1, self.results[stats_key][p]['successful_messages'])
                    missed = self.results[stats_key][p]['missed_deadlines']
                    deadline_rates[p] = 1.0 - (missed / successful)
                else:
                    deadline_rates[p] = 0
        
        if not deadline_rates:
            print("警告: 无法计算截止时间满足率")
            return
        
        plt.figure(figsize=(12, 6))
        bars = plt.bar(deadline_rates.keys(), deadline_rates.values(), color=sns.color_palette("colorblind", len(protocols)))
        
        plt.ylabel('截止时间满足率')
        plt.xlabel('通信协议')
        plt.title('不同协议的截止时间满足率对比')
        plt.ylim(0, 1.0)
        
        # 在柱状图上添加数值标签
        for bar in bars:
            height = bar.get_height()
            plt.text(bar.get_x() + bar.get_width()/2., height + 0.01,
                    f'{height:.2%}', ha='center', va='bottom')
        
        plt.grid(axis='y', alpha=0.3)
        plt.tight_layout()
        plt.savefig(os.path.join(self.output_dir, 'deadline_meet_rates.png'))
        plt.close()
    
    def plot_delay_distribution(self):
        """绘制不同协议的延迟分布图"""
        protocols, stats_key = self._get_protocols_and_stats_key()
        if not protocols:
            print("警告: 找不到协议信息")
            return
        
        plt.figure(figsize=(12, 8))
        has_data = False
        
        colors = sns.color_palette("colorblind", len(protocols))
        
        for i, p in enumerate(protocols):
            # 检查延迟分布数据
            if p not in self.results[stats_key]:
                continue
                
            p_stats = self.results[stats_key][p]
            delays = None
            
            # 尝试多种可能的数据格式
            if 'delay_distribution' in p_stats:
                # 格式1: 延迟分布字典
                delays_dict = p_stats['delay_distribution']
                # 将字符串键转换为浮点数
                delays_dict = {float(k): v for k, v in delays_dict.items()}
                x = sorted(delays_dict.keys())
                y = [delays_dict[k] for k in x]
                
                plt.plot(x, y, '-o', linewidth=2, markersize=4, label=p, color=colors[i])
                has_data = True
                
            elif 'delays' in p_stats:
                # 格式2: 直接保存的延迟列表
                delays = p_stats['delays']
                if delays:
                    # 创建一个更平滑的直方图
                    weights = np.ones_like(delays) / len(delays)
                    plt.hist(delays, bins=min(30, len(set(delays))), alpha=0.6, 
                             weights=weights, label=p, color=colors[i])
                    has_data = True
                    
                    # 添加核密度估计曲线
                    if len(delays) > 3:  # 需要足够的数据点才能计算KDE
                        try:
                            kde_x = np.linspace(min(delays), max(delays), 100)
                            kde = gaussian_kde(delays)
                            plt.plot(kde_x, kde(kde_x), '-', linewidth=2, color=colors[i])
                        except:
                            # 如果KDE计算失败，则跳过
                            pass
                    
            elif 'avg_delay' in p_stats and 'total_messages' in p_stats:
                # 格式3: 只有平均延迟，没有分布 - 创建一个模拟分布
                avg_delay = p_stats['avg_delay']
                # 假设一个正态分布，标准差设为平均值的20%
                std_dev = avg_delay * 0.2
                # 生成100个样本点
                simulated_delays = np.random.normal(avg_delay, std_dev, 100)
                simulated_delays = simulated_delays[simulated_delays > 0]  # 去除负值
                
                weights = np.ones_like(simulated_delays) / len(simulated_delays)
                plt.hist(simulated_delays, bins=20, alpha=0.4, weights=weights,
                         label=f"{p} (模拟分布)", color=colors[i])
                
                # 添加平均值的垂直线
                plt.axvline(x=avg_delay, color=colors[i], linestyle='--', 
                            label=f"{p} 平均值: {avg_delay:.2f}ms")
                has_data = True
        
        if not has_data:
            print("警告: 没有延迟分布数据可用")
            plt.close()
            return
        
        plt.xlabel('传输延迟 (ms)')
        plt.ylabel('消息比例')
        plt.title('不同协议的延迟分布对比')
        plt.legend(loc='best')
        plt.grid(True, alpha=0.3)
        
        # 添加美化元素
        sns.despine()  # 去除上边框和右边框
        plt.tight_layout()
        
        # 保存高质量图片
        plt.savefig(os.path.join(self.output_dir, 'delay_distribution.png'), dpi=300)
        plt.close()
    
    def plot_dcdp_delay_components(self):
        """绘制DCDP协议的延迟组成分析图"""
        # 查找是否有DCDP协议数据
        _, stats_key = self._get_protocols_and_stats_key()
        if not stats_key or 'dcdp_protocol' not in self.results[stats_key]:
            print("警告: 找不到DCDP协议数据")
            return
        
        dcdp_stats = self.results[stats_key]['dcdp_protocol']
        
        # 查找延迟组成数据
        delay_components = {}
        if 'delay_components' in dcdp_stats:
            delay_components = dcdp_stats['delay_components']
        elif 'avg_propagation_delay' in dcdp_stats and 'avg_processing_delay' in dcdp_stats and 'avg_congestion_delay' in dcdp_stats:
            delay_components = {
                'propagation_delay': dcdp_stats['avg_propagation_delay'],
                'processing_delay': dcdp_stats['avg_processing_delay'],
                'queuing_delay': dcdp_stats['avg_congestion_delay']  # 适应不同的命名
            }
        
        if not delay_components:
            print("警告: 找不到DCDP协议延迟组成数据")
            return
        
        # 确保有所有需要的延迟组成部分
        for key in ['propagation_delay', 'processing_delay', 'queuing_delay']:
            if key not in delay_components:
                if key == 'queuing_delay' and 'congestion_delay' in delay_components:
                    # 名称可能不同
                    delay_components['queuing_delay'] = delay_components['congestion_delay']
                else:
                    delay_components[key] = 0
        
        labels = ['传播延迟', '处理延迟', '排队延迟']
        sizes = [delay_components.get('propagation_delay', 0), 
                delay_components.get('processing_delay', 0), 
                delay_components.get('queuing_delay', 0)]
        
        # 绘制饼图
        plt.figure(figsize=(10, 8))
        plt.pie(sizes, labels=labels, autopct='%1.1f%%', shadow=True, startangle=140)
        plt.axis('equal')  # Equal aspect ratio ensures that pie is drawn as a circle
        plt.title('DCDP协议延迟组成分析')
        plt.tight_layout()
        plt.savefig(os.path.join(self.output_dir, 'dcdp_delay_components.png'))
        plt.close()
        
        # 绘制柱状图
        plt.figure(figsize=(10, 6))
        bars = plt.bar(labels, sizes)
        plt.ylabel('延迟 (ms)')
        plt.title('DCDP协议延迟组成分析')
        
        # 在柱状图上添加数值标签
        for bar in bars:
            height = bar.get_height()
            plt.text(bar.get_x() + bar.get_width()/2., height + 0.5,
                    f'{height:.2f}ms', ha='center', va='bottom')
                    
        plt.grid(axis='y', alpha=0.3)
        plt.tight_layout()
        plt.savefig(os.path.join(self.output_dir, 'dcdp_delay_components_bar.png'))
        plt.close()
    
    def plot_performance_radar(self):
        """绘制协议性能雷达图"""
        protocols, stats_key = self._get_protocols_and_stats_key()
        if not protocols:
            print("警告: 找不到协议信息")
            return

        # 性能指标
        metrics = ['传输成功率', '紧急消息成功率', '截止时间满足率', '带宽效率', '能耗效率']
        n_metrics = len(metrics)
        
        # 设置极坐标系
        angles = np.linspace(0, 2*np.pi, n_metrics, endpoint=False).tolist()
        angles += angles[:1]  # 闭合图形
        
        fig, ax = plt.subplots(figsize=(10, 10), subplot_kw=dict(polar=True))
        
        # 为每个协议生成评分
        for p in protocols:
            if p not in self.results[stats_key]:
                continue
            
            scores = []
            p_stats = self.results[stats_key][p]
            
            # 传输成功率
            if 'delivery_rate' in p_stats:
                scores.append(p_stats['delivery_rate'])
            elif 'successful_messages' in p_stats and 'total_messages' in p_stats:
                total = max(1, p_stats['total_messages'])
                scores.append(p_stats['successful_messages'] / total)
            else:
                scores.append(0)
            
            # 紧急消息成功率
            if 'emergency_delivery_rate' in p_stats:
                scores.append(p_stats['emergency_delivery_rate'])
            elif 'emergency_messages_handled' in p_stats and 'emergency_messages' in p_stats:
                if p_stats['emergency_messages'] > 0:
                    scores.append(p_stats['emergency_messages_handled'] / p_stats['emergency_messages'])
                else:
                    scores.append(0)
            else:
                scores.append(0)
            
            # 截止时间满足率
            if 'deadline_meet_rate' in p_stats:
                scores.append(p_stats['deadline_meet_rate'])
            elif 'deadline_met' in p_stats and 'deadline_messages' in p_stats:
                if p_stats['deadline_messages'] > 0:
                    scores.append(p_stats['deadline_met'] / p_stats['deadline_messages'])
                else:
                    scores.append(0)
            else:
                scores.append(0)
            
            # 带宽效率 (自定义指标)
            if 'bandwidth_efficiency' in p_stats:
                scores.append(p_stats['bandwidth_efficiency'])
            else:
                # 简单估算: 成功率/平均延迟的比值，归一化到0-1范围
                if 'avg_delay' in p_stats and p_stats['avg_delay'] > 0:
                    efficiency = scores[0] / (p_stats['avg_delay'] / 100)  # 简单归一化
                    scores.append(min(1.0, efficiency))
                else:
                    scores.append(0.5)  # 默认中等
            
            # 能耗效率 (自定义指标)
            if 'energy_efficiency' in p_stats:
                scores.append(p_stats['energy_efficiency'])
            else:
                # 默认值
                scores.append(0.5)
            
            # 闭合图形
            scores += scores[:1]
            
            # 绘制雷达图
            ax.plot(angles, scores, linewidth=2, label=p)
            ax.fill(angles, scores, alpha=0.1)
        
        # 设置刻度标签
        ax.set_xticks(angles[:-1])
        ax.set_xticklabels(metrics)
        
        # 设置Y轴刻度范围
        ax.set_yticks([0.2, 0.4, 0.6, 0.8, 1.0])
        ax.set_yticklabels(['0.2', '0.4', '0.6', '0.8', '1.0'])
        ax.set_ylim(0, 1)
        
        plt.title('协议性能雷达图', size=15, y=1.1)
        plt.legend(loc='upper right', bbox_to_anchor=(0.1, 0.1))
        plt.tight_layout()
        plt.savefig(os.path.join(self.output_dir, 'performance_radar.png'))
        plt.close()
    
    def plot_trajectories(self):
        """绘制UAV轨迹图"""
        # 检查是否有轨迹数据
        if 'trajectories' not in self.results:
            print("警告: 找不到轨迹数据")
            return
        
        trajectories = self.results['trajectories']
        if not trajectories:
            print("警告: 轨迹数据为空")
            return
        
        plt.figure(figsize=(12, 10))
        
        # 确定结果中有多少个UAV
        uav_ids = set()
        for snapshot in trajectories:
            for uav_id in snapshot:
                uav_ids.add(uav_id)
        
        # 为每个UAV分配不同的颜色
        colors = plt.cm.jet(np.linspace(0, 1, len(uav_ids)))
        uav_colors = {uav_id: colors[i] for i, uav_id in enumerate(sorted(uav_ids))}
        
        # 提取每个UAV的轨迹
        uav_paths = {uav_id: [] for uav_id in uav_ids}
        
        for snapshot in trajectories:
            for uav_id, position in snapshot.items():
                # 确保位置是一个有效的坐标
                if isinstance(position, list) and len(position) >= 2:
                    uav_paths[uav_id].append((position[0], position[1]))
        
        # 绘制每个UAV的轨迹和当前位置
        for uav_id, path in uav_paths.items():
            if path:
                # 轨迹线
                x, y = zip(*path)
                plt.plot(x, y, '-', color=uav_colors[uav_id], alpha=0.6, linewidth=1.5)
                
                # 起点 (空心圆)
                plt.plot(x[0], y[0], 'o', color=uav_colors[uav_id], markerfacecolor='white', 
                         markersize=8, markeredgewidth=2)
                
                # 终点 (实心圆)
                plt.plot(x[-1], y[-1], 'o', color=uav_colors[uav_id], markersize=6)
                
                # 添加UAV ID标签
                plt.text(x[-1], y[-1], f" UAV {uav_id}", fontsize=9, color=uav_colors[uav_id],
                         verticalalignment='center')
        
        plt.title('UAV轨迹图')
        plt.xlabel('X坐标')
        plt.ylabel('Y坐标')
        plt.grid(True, alpha=0.3)
        plt.axis('equal')  # 保持X和Y轴比例一致
        plt.tight_layout()
        plt.savefig(os.path.join(self.output_dir, 'uav_trajectories.png'))
        plt.close()
    
    def plot_protocol_comparison(self):
        """绘制协议性能综合对比图"""
        protocols, stats_key = self._get_protocols_and_stats_key()
        if not protocols:
            print("警告: 找不到协议信息")
            return
        
        # 设置图表布局
        fig = plt.figure(figsize=(15, 12))
        gs = GridSpec(2, 2, figure=fig)
        
        # 绘制传输成功率对比
        ax1 = fig.add_subplot(gs[0, 0])
        delivery_rates = {}
        for p in protocols:
            if p in self.results[stats_key]:
                if 'delivery_rate' in self.results[stats_key][p]:
                    delivery_rates[p] = self.results[stats_key][p]['delivery_rate']
                elif 'successful_messages' in self.results[stats_key][p] and 'total_messages' in self.results[stats_key][p]:
                    total = max(1, self.results[stats_key][p]['total_messages'])
                    success = self.results[stats_key][p]['successful_messages']
                    delivery_rates[p] = success / total
        
        if delivery_rates:
            bars1 = ax1.bar(delivery_rates.keys(), delivery_rates.values())
            ax1.set_ylabel('传输成功率')
            ax1.set_title('传输成功率对比')
            ax1.set_ylim(0, 1.0)
            for bar in bars1:
                height = bar.get_height()
                ax1.text(bar.get_x() + bar.get_width()/2., height + 0.01, f'{height:.2f}', ha='center', va='bottom')
        
        # 绘制平均延迟对比
        ax2 = fig.add_subplot(gs[0, 1])
        delays = {}
        for p in protocols:
            if p in self.results[stats_key] and 'avg_delay' in self.results[stats_key][p]:
                delays[p] = self.results[stats_key][p]['avg_delay']
        
        if delays:
            bars2 = ax2.bar(delays.keys(), delays.values())
            ax2.set_ylabel('平均延迟 (ms)')
            ax2.set_title('平均延迟对比')
            for bar in bars2:
                height = bar.get_height()
                ax2.text(bar.get_x() + bar.get_width()/2., height + 1, f'{height:.2f}', ha='center', va='bottom')
        
        # 绘制紧急消息传输成功率
        ax3 = fig.add_subplot(gs[1, 0])
        emergency_rates = {}
        for p in protocols:
            if p in self.results[stats_key]:
                if 'emergency_delivery_rate' in self.results[stats_key][p]:
                    emergency_rates[p] = self.results[stats_key][p]['emergency_delivery_rate']
                elif ('emergency_messages_handled' in self.results[stats_key][p] and 
                      'emergency_messages' in self.results[stats_key][p] and 
                      self.results[stats_key][p]['emergency_messages'] > 0):
                    emergency_rates[p] = (self.results[stats_key][p]['emergency_messages_handled'] / 
                                         self.results[stats_key][p]['emergency_messages'])
                else:
                    emergency_rates[p] = 0
        
        if emergency_rates:
            bars3 = ax3.bar(emergency_rates.keys(), emergency_rates.values())
            ax3.set_ylabel('紧急消息传输成功率')
            ax3.set_title('紧急消息传输成功率对比')
            ax3.set_ylim(0, 1.0)
            for bar in bars3:
                height = bar.get_height()
                ax3.text(bar.get_x() + bar.get_width()/2., height + 0.01, f'{height:.2f}', ha='center', va='bottom')
        
        # 绘制截止时间满足率
        ax4 = fig.add_subplot(gs[1, 1])
        deadline_rates = {}
        for p in protocols:
            if p in self.results[stats_key]:
                if 'deadline_meet_rate' in self.results[stats_key][p]:
                    deadline_rates[p] = self.results[stats_key][p]['deadline_meet_rate']
                elif 'deadline_met' in self.results[stats_key][p] and 'deadline_messages' in self.results[stats_key][p]:
                    total = max(1, self.results[stats_key][p]['deadline_messages'])
                    met = self.results[stats_key][p]['deadline_met']
                    deadline_rates[p] = met / total
                elif 'missed_deadlines' in self.results[stats_key][p] and 'successful_messages' in self.results[stats_key][p]:
                    if self.results[stats_key][p]['successful_messages'] > 0:
                        deadline_rates[p] = 1.0 - (self.results[stats_key][p]['missed_deadlines'] / 
                                                  self.results[stats_key][p]['successful_messages'])
                    else:
                        deadline_rates[p] = 0
                else:
                    deadline_rates[p] = 0
        
        if deadline_rates:
            bars4 = ax4.bar(deadline_rates.keys(), deadline_rates.values())
            ax4.set_ylabel('截止时间满足率')
            ax4.set_title('截止时间满足率对比')
            ax4.set_ylim(0, 1.0)
            for bar in bars4:
                height = bar.get_height()
                ax4.text(bar.get_x() + bar.get_width()/2., height + 0.01, f'{height:.2f}', ha='center', va='bottom')
        
        plt.tight_layout()
        plt.savefig(os.path.join(self.output_dir, 'protocol_comparison.png'))
        plt.close()
    
    def plot_separate_metrics(self):
        """绘制四个单独的性能指标图表，不包含lora协议"""
        protocols, stats_key = self._get_protocols_and_stats_key()
        if not protocols:
            print("警告: 找不到协议信息")
            return
        
        # 去除lora协议
        protocols = [p for p in protocols if p.lower() != 'lora']
        if not protocols:
            print("警告: 去除lora后没有剩余协议")
            return
        
        # 设置好看的颜色方案
        colors = ['#3498db', '#e74c3c', '#2ecc71', '#f39c12', '#9b59b6', '#1abc9c']
        
        # 1. 传输成功率
        success_rates = {}
        for p in protocols:
            if p in self.results[stats_key]:
                if 'delivery_rate' in self.results[stats_key][p]:
                    success_rates[p] = self.results[stats_key][p]['delivery_rate']
                elif 'successful_messages' in self.results[stats_key][p] and 'total_messages' in self.results[stats_key][p]:
                    total = max(1, self.results[stats_key][p]['total_messages'])
                    success = self.results[stats_key][p]['successful_messages']
                    success_rates[p] = success / total
        
        if success_rates:
            plt.figure(figsize=(10, 6))
            bars = plt.bar(success_rates.keys(), success_rates.values(), color=colors[:len(protocols)])
            plt.ylabel('传输成功率')
            plt.title('传输成功率对比')
            plt.ylim(0, max(success_rates.values()) * 1.2)  # 留出足够空间显示标签
            
            # 在柱状图上添加数值标签
            for bar in bars:
                height = bar.get_height()
                plt.text(bar.get_x() + bar.get_width()/2., height + 0.01,
                       f'{height:.2f}', ha='center', va='bottom')
            
            plt.grid(axis='y', alpha=0.3)
            plt.tight_layout()
            
            # 添加图例
            plt.legend(bars, success_rates.keys(), title="通信协议")
            
            plt.savefig(os.path.join(self.output_dir, 'success_rate_comparison.png'), dpi=300)
            plt.close()
        
        # 2. 平均延迟
        avg_delays = {}
        for p in protocols:
            if p in self.results[stats_key] and 'avg_delay' in self.results[stats_key][p]:
                avg_delays[p] = self.results[stats_key][p]['avg_delay']
        
        if avg_delays:
            plt.figure(figsize=(10, 6))
            bars = plt.bar(avg_delays.keys(), avg_delays.values(), color=colors[:len(protocols)])
            plt.ylabel('平均延迟 (ms)')
            plt.title('平均延迟对比')
            
            # 在柱状图上添加数值标签
            for bar in bars:
                height = bar.get_height()
                plt.text(bar.get_x() + bar.get_width()/2., height + 1,
                       f'{height:.2f}ms', ha='center', va='bottom')
            
            plt.grid(axis='y', alpha=0.3)
            plt.tight_layout()
            
            # 添加图例
            plt.legend(bars, avg_delays.keys(), title="通信协议")
            
            plt.savefig(os.path.join(self.output_dir, 'avg_delay_comparison.png'), dpi=300)
            plt.close()
        
        # 3. 紧急消息成功率
        emergency_rates = {}
        for p in protocols:
            if p in self.results[stats_key]:
                if 'emergency_delivery_rate' in self.results[stats_key][p]:
                    emergency_rates[p] = self.results[stats_key][p]['emergency_delivery_rate']
                elif ('emergency_messages_handled' in self.results[stats_key][p] and 
                      'emergency_messages' in self.results[stats_key][p] and 
                      self.results[stats_key][p]['emergency_messages'] > 0):
                    emergency_rates[p] = (self.results[stats_key][p]['emergency_messages_handled'] / 
                                         self.results[stats_key][p]['emergency_messages'])
        
        if emergency_rates:
            plt.figure(figsize=(10, 6))
            bars = plt.bar(emergency_rates.keys(), emergency_rates.values(), color=colors[:len(protocols)])
            plt.ylabel('紧急消息传输成功率')
            plt.title('紧急消息传输成功率对比')
            plt.ylim(0, max(emergency_rates.values()) * 1.2)  # 留出足够空间显示标签
            
            # 在柱状图上添加数值标签
            for bar in bars:
                height = bar.get_height()
                plt.text(bar.get_x() + bar.get_width()/2., height + 0.01,
                       f'{height:.2f}', ha='center', va='bottom')
            
            plt.grid(axis='y', alpha=0.3)
            plt.tight_layout()
            
            # 添加图例
            plt.legend(bars, emergency_rates.keys(), title="通信协议")
            
            plt.savefig(os.path.join(self.output_dir, 'emergency_rate_comparison.png'), dpi=300)
            plt.close()
        
        # 4. 截止时间满足率
        deadline_rates = {}
        for p in protocols:
            if p in self.results[stats_key]:
                if 'deadline_meet_rate' in self.results[stats_key][p]:
                    deadline_rates[p] = self.results[stats_key][p]['deadline_meet_rate']
                elif 'deadline_met' in self.results[stats_key][p] and 'deadline_messages' in self.results[stats_key][p]:
                    total = max(1, self.results[stats_key][p]['deadline_messages'])
                    met = self.results[stats_key][p]['deadline_met']
                    deadline_rates[p] = met / total
                elif 'missed_deadlines' in self.results[stats_key][p] and 'successful_messages' in self.results[stats_key][p]:
                    if self.results[stats_key][p]['successful_messages'] > 0:
                        deadline_rates[p] = 1.0 - (self.results[stats_key][p]['missed_deadlines'] / 
                                                self.results[stats_key][p]['successful_messages'])
        
        if deadline_rates:
            plt.figure(figsize=(10, 6))
            bars = plt.bar(deadline_rates.keys(), deadline_rates.values(), color=colors[:len(protocols)])
            plt.ylabel('截止时间满足率')
            plt.title('截止时间满足率对比')
            plt.ylim(0, max(deadline_rates.values()) * 1.2)  # 留出足够空间显示标签
            
            # 在柱状图上添加数值标签
            for bar in bars:
                height = bar.get_height()
                plt.text(bar.get_x() + bar.get_width()/2., height + 0.01,
                       f'{height:.2f}', ha='center', va='bottom')
            
            plt.grid(axis='y', alpha=0.3)
            plt.tight_layout()
            
            # 添加图例
            plt.legend(bars, deadline_rates.keys(), title="通信协议")
            
            plt.savefig(os.path.join(self.output_dir, 'deadline_rate_comparison.png'), dpi=300)
            plt.close()
        
        print(f"四个单独的性能指标图表已保存至 {self.output_dir} 目录")
    
    def plot_all(self):
        """生成所有可视化图表"""
        print("正在生成可视化结果...")
        
        # 创建图表目录
        if not os.path.exists(self.output_dir):
            os.makedirs(self.output_dir)
        
        # 绘制所有图表
        try:
            self.plot_delivery_rates()
        except Exception as e:
            print(f"绘制传输成功率图表时出错: {e}")
        
        try:
            self.plot_average_delays()
        except Exception as e:
            print(f"绘制平均延迟图表时出错: {e}")
        
        try:
            self.plot_emergency_delivery_rates()
        except Exception as e:
            print(f"绘制紧急消息传输成功率图表时出错: {e}")
        
        try:
            self.plot_deadline_meet_rates()
        except Exception as e:
            print(f"绘制截止时间满足率图表时出错: {e}")
        
        try:
            self.plot_delay_distribution()
        except Exception as e:
            print(f"绘制延迟分布图表时出错: {e}")
        
        try:
            self.plot_dcdp_delay_components()
        except Exception as e:
            print(f"绘制DCDP协议延迟组成图表时出错: {e}")
        
        try:
            self.plot_protocol_comparison()
        except Exception as e:
            print(f"绘制协议对比图表时出错: {e}")
        
        try:
            self.plot_performance_radar()
        except Exception as e:
            print(f"绘制性能雷达图时出错: {e}")
        
        try:
            self.plot_trajectories()
        except Exception as e:
            print(f"绘制UAV轨迹图时出错: {e}")
        
        try:
            self.plot_separate_metrics()
        except Exception as e:
            print(f"绘制四个单独的性能指标图表时出错: {e}")
        
        print(f"所有可视化结果已保存到目录: {self.output_dir}")
        
        # 生成摘要报告
        try:
            self.generate_summary_report()
        except Exception as e:
            print(f"生成摘要报告时出错: {e}")
    
    def generate_summary_report(self):
        """生成仿真结果摘要报告，保存为JSON文件"""
        protocols, stats_key = self._get_protocols_and_stats_key()
        if not protocols:
            print("警告: 找不到协议信息，无法生成摘要报告")
            return
        
        summary = {
            "simulation_info": {
                "timestamp": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
                "num_protocols": len(protocols),
                "protocols": protocols,
                "figures_dir": self.output_dir
            },
            "protocol_performance": {}
        }
        
        # 收集每个协议的关键性能指标
        for p in protocols:
            if p in self.results[stats_key]:
                p_stats = self.results[stats_key][p]
                
                # 提取或计算主要性能指标
                protocol_summary = {}
                
                # 传输成功率
                if 'delivery_rate' in p_stats:
                    protocol_summary['delivery_rate'] = p_stats['delivery_rate']
                elif 'successful_messages' in p_stats and 'total_messages' in p_stats:
                    if p_stats['total_messages'] > 0:
                        protocol_summary['delivery_rate'] = p_stats['successful_messages'] / p_stats['total_messages']
                
                # 平均延迟
                if 'avg_delay' in p_stats:
                    protocol_summary['avg_delay'] = p_stats['avg_delay']
                
                # 紧急消息成功率
                if 'emergency_delivery_rate' in p_stats:
                    protocol_summary['emergency_rate'] = p_stats['emergency_delivery_rate']
                elif 'emergency_messages_handled' in p_stats and 'emergency_messages' in p_stats:
                    if p_stats['emergency_messages'] > 0:
                        protocol_summary['emergency_rate'] = p_stats['emergency_messages_handled'] / p_stats['emergency_messages']
                
                # 截止时间满足率
                if 'deadline_meet_rate' in p_stats:
                    protocol_summary['deadline_rate'] = p_stats['deadline_meet_rate']
                elif 'deadline_met' in p_stats and 'deadline_messages' in p_stats:
                    if p_stats['deadline_messages'] > 0:
                        protocol_summary['deadline_rate'] = p_stats['deadline_met'] / p_stats['deadline_messages']
                
                # 如果是DCDP协议，包含延迟分解
                if p == 'dcdp_protocol':
                    delay_components = {}
                    if 'delay_components' in p_stats:
                        delay_components = p_stats['delay_components']
                    elif ('avg_propagation_delay' in p_stats and 
                          'avg_processing_delay' in p_stats and 
                          'avg_congestion_delay' in p_stats):
                        delay_components = {
                            'propagation_delay': p_stats['avg_propagation_delay'],
                            'processing_delay': p_stats['avg_processing_delay'],
                            'queuing_delay': p_stats['avg_congestion_delay']
                        }
                    if delay_components:
                        protocol_summary['delay_components'] = delay_components
                
                summary['protocol_performance'][p] = protocol_summary
        
        # 保存摘要报告
        summary_file = os.path.join(self.output_dir, 'summary_report.json')
        with open(summary_file, 'w', encoding='utf-8') as f:
            json.dump(summary, f, indent=4, ensure_ascii=False)
        
        print(f"摘要报告已保存到: {summary_file}") 